home *** CD-ROM | disk | FTP | other *** search
Modula Implementation | 1996-12-18 | 7.0 KB | 192 lines | [TEXT/3PRM] |
- implementation module Mandelbrot
-
- import StdReal,StdInt,StdMisc,StdBool,StdClass
- import FractalTypes, Complex
-
- :: FractalUpdArea
- = { updlayer:: !Layer
- , updgrain:: !GrainSize
- , beginx :: !Int
- , endx :: !Int
- , endline :: !Int
- }
-
- // Drawing the image grained.
- PaintSpot :: !Rectangle !Int !FunctionState !Picture -> Picture
- PaintSpot rect color {colours,depth} p
- | color==depth = PaintRectangle rect (RGB 0.0 0.0 0.0) p
- | otherwise = PaintRectangle rect (IndexToColor colours color) p
- where
- PaintRectangle :: !Rectangle !Colour !Picture -> Picture
- PaintRectangle rect=:((x,y),(x`,y`)) rgb_color p
- # p = SetPenColour rgb_color p
- p = MovePenTo (x,y) p
- | 1==x`-x && 1==y`-y = LinePenTo (x,y) p
- | otherwise = FillRectangle rect p
-
- IndexToColor :: !Colours Int -> Colour
- IndexToColor (rs,ri,gs,gi,bs,bi) color
- = RGB red green blue
- where
- red = toReal (ri * ReverseBits (1 << rs) color 0) / rfac
- green = toReal (gi * ReverseBits (1 << gs) color 0) / gfac
- blue = toReal (bi * ReverseBits (1 << bs) color 0) / bfac
- rfac = toReal (32704 >> rs)
- gfac = toReal (32704 >> gs)
- bfac = toReal (32704 >> bs)
-
- ReverseBits :: !Int Int !Int -> Int
- ReverseBits mask number result
- | mask>256 = result
- | (number bitand mask)==0 = ReverseBits mask` number result`
- | otherwise = ReverseBits mask` number (inc result`)
- where
- mask` = mask << 1
- result`= result << 1
-
- // Update a specific area of the image.
- UpdateFractalArea :: Rectangle *FractalState -> (*FractalState,DrawFunction)
- UpdateFractalArea rect state=:{funstate,drawstate={layer,grain,line}}
- = (state,LazyDrawArea upd firstline funstate)
- where
- (upd,firstline) = CalculateUpdate rect layer grain
-
- CalculateUpdate :: !Rectangle !Layer !GrainSize -> (!FractalUpdArea,!Int)
- CalculateUpdate ((x1,y1),(x2,y2)) layer n
- = ({updlayer=layer,updgrain=n,beginx=beginx,endx=endx,endline=endline},beginline)
- where
- beginx = x1 / n*n
- endx = if (x2 mod n == 0) x2 ((x2/n+1)*n)
- beginline = y1 / n*n
- endline = if (y2 mod n == 0) y2 ((y2/n+1)*n)
-
- LazyDrawArea :: !FractalUpdArea !Int !FunctionState !Picture -> Picture
- LazyDrawArea upd=:{updlayer,updgrain,beginx,endx,endline} line state pic
- | line>=endline = pic
- | otherwise = LazyDrawArea upd (line+updgrain) state (LazyDrawSpots` (beginx,line) endx updgrain updlayer state pic)
- where
- LazyDrawSpots` :: !Point !Int !GrainSize !Layer !FunctionState !Picture -> Picture
- LazyDrawSpots` point=:(x,y) h n l funcs pic
- | x>h = pic
- | otherwise = LazyDrawSpots` (xn,y) h n l funcs (PaintSpot ((x,y),(xn,yn)) value funcs pic)
- where
- xn = x+n
- yn = y+n
- value = Fractal_color point funcs
-
- // The actual calculations
- Fractal_color :: !Point !FunctionState -> Int
- Fractal_color (x,y) {area={center=(centerx,centery),width,height},depth,fun}
- = depth` mod NrOfColours
- where
- depth` = Calculate fun depth rx ry
- rx = centerx - width /2.0 + (toReal x * width) / toReal ScreenWidth
- ry = centery - height/2.0 + (toReal y * height)/ toReal ScreenHeight
-
- Calculate :: !FractalFunction !Int !Real !Real -> Int
- Calculate MSquare maxd rx ry = MandelSquare maxd 0 0.0 0.0 rx ry
- where
- MandelSquare :: !Int !Int !Real !Real !Real !Real -> Int
- MandelSquare maxdepth depth x y bx by
- | maxdepth==depth = maxdepth
- | sx+sy>2.8 = depth
- | otherwise = MandelSquare maxdepth (inc depth) (sx-sy-bx) (pxy+pxy-by) bx by
- where
- sx = x*x
- sy = y*y
- pxy = x*y
- Calculate MCube maxd rx ry = MandelCube maxd 0 (0.0,0.0) (rx,ry)
- where
- MandelCube :: !Int !Int !ComplexNum !ComplexNum -> Int
- MandelCube maxdepth depth zn c
- | maxdepth==depth = maxdepth
- | FakeAbsC znp1 > 4.0 = depth
- | otherwise = MandelCube maxdepth (inc depth) znp1 c
- where
- znp1 = AddC c (MulC zn (MulC zn zn))
- Calculate MSin maxd rx ry = MandelSin maxd 0 (0.0,0.0) (rx,ry)
- where
- MandelSin :: !Int !Int !ComplexNum !ComplexNum -> Int
- MandelSin maxdepth depth zn c
- | maxdepth==depth = maxdepth
- | FakeAbsC znp1 > 4.0 = depth
- | otherwise = MandelSin maxdepth (inc depth) znp1 c
- where
- znp1 = AddC c (SinC zn)
- Calculate MCos maxd rx ry = MandelCos maxd 0 (0.0,0.0) (rx,ry)
- where
- MandelCos :: !Int !Int !ComplexNum !ComplexNum -> Int
- MandelCos maxdepth depth zn c
- | maxdepth==depth = maxdepth
- | FakeAbsC znp1 > 4.0 = depth
- | otherwise = MandelCos maxdepth (inc depth) znp1 c
- where
- znp1 = AddC c (CosC zn)
- Calculate MExp maxd rx ry = MandelExp maxd 0 (0.0,0.0) (rx,ry)
- where
- MandelExp :: Int Int ComplexNum ComplexNum -> Int
- MandelExp maxdepth depth zn c
- | maxdepth==depth = maxdepth
- | FakeAbsC znp1 > 4.0 = depth
- | otherwise = MandelExp maxdepth (inc depth) znp1 c
- where
- znp1 = AddC c (ExpC zn)
-
- // Timer device -> draw one line at a time
- DrawFractal :: TimerState *FractalState IO -> (*FractalState,IO)
- DrawFractal _ state=:{drawstate={grain=0}} io
- = DoStopDrawing {state & drawstate={state.drawstate & grain=1}} io
- DrawFractal _ fstate io
- = (fstate`,EnableTimer TimerID io`)
- where
- (fstate`,io`) = DrawFractalLine fstate (DisableTimer TimerID io)
-
- // Draw one line of the image.
- DrawFractalLine :: !*FractalState !IO -> (!*FractalState,!IO)
- DrawFractalLine state=:{funstate,drawstate={layer,grain,line}} io
- | line>=ScreenHeight = (SetDrawState {layer=dec layer,grain=grain>>1,line=0} state,io)
- | otherwise = (SetDrawState {layer=layer,grain=grain,line=line+grain} state,DrawInWindow MyWindow drawfs io)
- with
- drawfs = [LazyDrawSpots (0,line) (ScreenWidth,ScreenHeight) grain layer funstate]
- where
- LazyDrawSpots :: !Point !Point !GrainSize !Layer !FunctionState !Picture -> Picture
- LazyDrawSpots point=:(x,y) dim=:(h,v) n l funcs pic
- | x>h = pic
- | drawnspot = LazyDrawSpots (xn,y) dim n l funcs pic
- | otherwise = LazyDrawSpots (xn,y) dim n l funcs (PaintSpot ((x,y),(xn,yn)) value funcs pic)
- where
- drawnspot = 0==(1 bitand (x bitor y) >> l) && x<>0 && y<>0
- xn = x+n
- yn = y+n
- value = Fractal_color point funcs
-
- // Drawing has been stopped -> enable/disable menuitems/menus
- DoStopDrawing :: *FractalState IO -> (*FractalState, IO)
- DoStopDrawing state io
- # io = DisableTimer TimerID io
- io = EnableMenus [OptionsID] io
- io = DisableMenuItems [StopDrawID,ContinueID] io
- io = EnableMenuItems [DrawID] io
- = (state,io)
-
- // Set initial layer and grainsize.
- InitDrawState :: *FractalState -> *FractalState
- InitDrawState state = SetDrawState {layer=layer,grain=size,line=0} state
- where
- (layer,size) = Log2AndPower (max ScreenHeight ScreenWidth)
-
- Log2AndPower :: !Int -> (!Int,!Int)
- Log2AndPower n
- | halfpower==n = (log2_1,halfpower)
- | otherwise = (log2, power)
- where
- power = 1<<log2
- halfpower = 1<<log2_1
- log2 = Log2 n
- log2_1 = log2-1
-
- Log2 :: !Int -> Int
- Log2 n
- | n==1 = 1
- | otherwise = (Log2 (n>>1))+1
-